package com.atguigu.gmall.activity.listener;

import com.atguigu.gmall.activity.config.CacheHelper;
import com.atguigu.gmall.activity.mapper.SeckillGoodsMapper;
import com.atguigu.gmall.activity.utils.DateUtil;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.model.activity.SeckillGoods;
import com.atguigu.gmall.model.activity.UserRecode;
import com.atguigu.gmall.task.config.MqConst;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.Date;
import java.util.List;

/**
 * @author: 李旭
 * @create: 2021-07-28 10:04
 * <p>
 * 秒杀消费方
 **/
@Component
public class SeckillConsumer {


    @Autowired
    private SeckillGoodsMapper seckillGoodsMapper;
    @Autowired
    private RedisTemplate redisTemplate;


    //秒杀继续  监听器
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = MqConst.QUEUE_SECKILL_USER, durable = "true", autoDelete = "false"),
            exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_SECKILL_USER),
            key = MqConst.ROUTING_SECKILL_USER
    ))
    public void receiverMessage12(UserRecode userRecode,Channel channel, Message message) {
        try{
//            1、本地缓存（状态位）
            String state = (String) CacheHelper.get(userRecode.getSkuId().toString());
            if(!"1".equals(state)){
                //无货
                System.out.println("无货");
                channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
                return;
            }
//            2、校验用户是否来过  true   setnx 成功 之前没有来
            Boolean isCome = redisTemplate.opsForValue().setIfAbsent(
                    RedisConst.SECKILL_USER + userRecode.getUserId() + ":"
                            + userRecode.getSkuId(), "ccc");
            if(!isCome){
                System.out.println("来过了");
                channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
                return;
            }
//            3、获取商品ID
            Object skuIdFromRedis = redisTemplate.opsForList().rightPop(RedisConst.SECKILL_STOCK_PREFIX
                    + userRecode.getSkuId());
            if(null == skuIdFromRedis){
                //无货  变更状态位  由原来的 1 改为 0  使用广播
                redisTemplate.convertAndSend("seckillpush",
                        userRecode.getSkuId() + ":0");
                channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
                return;
            }
//            4、抢购成功
            redisTemplate.opsForValue().set(RedisConst.SECKILL_ORDERS + userRecode.getUserId(),
                    skuIdFromRedis);
            //.....
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }





    //接收闹铃  将DB中数据导入缓存中
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = MqConst.QUEUE_TASK_1, durable = "true", autoDelete = "false"),
            exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_TASK),
            key = MqConst.ROUTING_TASK_1
    ))
    public void receiverMessage(Channel channel, Message message) {
        try {
            System.out.println("半夜0点开始干活");
/*            select *
                    from seckill_goods
            where `status` = 1
            and  DATE_FORMAT(start_time,'%Y-%m-%d') = '2021-07-28'
            and stock_count > 0*/
            //1:从DB中查询数据  1.1 审核通过  1.2 活动当前秒杀商品  1.3 剩余库存数大于0
            QueryWrapper<SeckillGoods> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("status", "1");
            queryWrapper.gt("stock_count", 0);
            QueryWrapper<SeckillGoods> eq = queryWrapper.eq("DATE_FORMAT(start_time,'%Y-%m-%d')",
                    DateUtil.formatDate(new Date()));

            // eq  =  , greater  ge >=   gt >   lt <  le <=
            List<SeckillGoods> seckillGoodList = seckillGoodsMapper.selectList(queryWrapper);
            //2:将数据放入缓存  值类型  Hash  ZSet  List Set
            for (SeckillGoods seckillGoods : seckillGoodList) {
                // Map h = new HashM
                // h.put(hk,hv)
                //2.1 秒杀数据
                if (!redisTemplate.opsForHash().hasKey(RedisConst.SECKILL_GOODS,
                        seckillGoods.getSkuId().toString())) {
                    //保存数据到缓存中
                    redisTemplate.opsForHash().put(RedisConst.SECKILL_GOODS,
                            seckillGoods.getSkuId().toString(), seckillGoods);
                    //2.2 防超卖  将秒杀商品的ID  放到redis List类型
                    Long[] skuIds = buildSkuIds(seckillGoods);
                    redisTemplate.opsForList().leftPushAll(
                            RedisConst.SECKILL_STOCK_PREFIX + seckillGoods.getSkuId(), skuIds);
                    //2.3:状态位  广播 的方式  到每一个秒杀微服务
                    redisTemplate.convertAndSend("seckillpush",
                            seckillGoods.getSkuId() + ":1");

                }
            }
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    //
    private Long[] buildSkuIds(SeckillGoods seckillGoods) {
        Long[] ids = new Long[seckillGoods.getStockCount()];
        for (Integer i = 0; i < seckillGoods.getStockCount(); i++) {
            ids[i] = seckillGoods.getSkuId();
        }
        return ids;
    }
}
